package com.dospyer.curator;

import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.locks.*;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.curator.utils.CloseableUtils;
import org.apache.zookeeper.CreateMode;

import java.util.ArrayList;
import java.util.List;

/**
 * @author : peigen
 * Date: 2021/7/21 上午9:36
 */
public class Application {
    public static void main(String[] args) {
        String connectionString = "192.168.100.230:30985,192.168.100.230:30986,192.168.100.230:30987";
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(10, 1);

        CuratorFramework client = CuratorFrameworkFactory.builder().
                connectString(connectionString)
                // 会话超时时间，默认60000ms
                .sessionTimeoutMs(60000)
                // 连接超时时间，默认15000ms
                .connectionTimeoutMs(15000)
                // 重试策略
                .retryPolicy(retryPolicy)
                .build();

        try {
            long start = System.currentTimeMillis();
            System.out.println("client.start() 开始");
            client.start();
            System.out.println("client.start() 结束，耗时：" + (System.currentTimeMillis()-start));

//            curatorDemo(client);

            // 可重入锁
            interProcessMutexDemo(client);
//
//        // 信号量 指定同时有多个线程获取到锁
//        interProcessSemaphoreV2Demo(client);
//
//        // 非可重入锁，基于 Semaphore 实现，允许获取锁的客户端的数量设置为了1
//        interProcessSemaphoreMutexDemo(client);
//
//        // 可重入读写锁
//        interProcessReadWriteLockDemo(client);
//
//        // multiLock
//        multiLockDemo(client);

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            CloseableUtils.closeQuietly(client);
        }
    }

    /**
     * multiLock
     *
     * @param client
     * @throws Exception
     */
    private static void multiLockDemo(CuratorFramework client) throws Exception {
        InterProcessLock lock1 = new InterProcessMutex(client, "/locks/lock_01");
        InterProcessLock lock2 = new InterProcessMutex(client, "/locks/lock_02");
        InterProcessLock lock3 = new InterProcessMutex(client, "/locks/lock_03");

        List<InterProcessLock> locks = new ArrayList<InterProcessLock>();
        locks.add(lock1);
        locks.add(lock2);
        locks.add(lock3);

        InterProcessMultiLock multiLock = new InterProcessMultiLock(locks);
        multiLock.acquire();
        multiLock.release();
    }

    /**
     * 可重入读写锁
     *
     * @param client
     * @throws Exception
     */
    private static void interProcessReadWriteLockDemo(CuratorFramework client) throws Exception {
        InterProcessReadWriteLock lock = new InterProcessReadWriteLock(
                client, "/locks/lock_01");
        lock.writeLock().acquire();
        lock.readLock().acquire();
        lock.readLock().release();
        lock.writeLock().release();
    }

    /**
     * 非可重入锁，基于 Semaphore 实现，允许获取锁的客户端的数量设置为了1
     *
     * @param client
     */
    private static void interProcessSemaphoreMutexDemo(CuratorFramework client) {
        InterProcessSemaphoreMutex lock = new InterProcessSemaphoreMutex(
                client, "/locks/lock_01");
    }

    /**
     * 信号量 指定同时有多个线程获取到锁
     *
     * @param client
     * @throws Exception
     */
    private static void interProcessSemaphoreV2Demo(CuratorFramework client) throws Exception {
        InterProcessSemaphoreV2 semaphore = new InterProcessSemaphoreV2(
                client, "/semaphores/semaphore_01", 3);
        Lease lease = semaphore.acquire();
        Thread.sleep(30000);
        semaphore.returnLease(lease);
    }

    /**
     * 可重入锁
     *
     * @param client
     * @throws Exception
     */
    private static void interProcessMutexDemo(CuratorFramework client) throws Exception {
        InterProcessMutex lock = new InterProcessMutex(client, "/locks/lock_01");
        lock.acquire();
        Thread.sleep(1000);
        lock.release();
        System.out.println("释放锁成功");
    }

    /**
     * curator 基础代码演示
     *
     * @param client
     * @throws Exception
     */
    private static void curatorDemo(CuratorFramework client) throws Exception {
        String path = client.create()
                // 创建znode，如果有必要就自动创建他的父目录
                .creatingParentsIfNeeded()
                .withProtection()
                // 使用临时顺序节点
                // 临时节点，当前这台机器如果自己宕机的话，他创建的这个临时节点就会自动消失
                // 顺序节点，在创建这个节点的时候，zk会自动按照顺序给创建的节点标上序号
                .withMode(CreateMode.PERSISTENT_SEQUENTIAL)
                .forPath("/user/dir", "hello world".getBytes());

        System.out.println(path);
    }
}
